今日Android小技巧:
不要用jadx和jd,反编译出的控制结构可能是错的,用jeb
第一次出Android题喵,出得烂不要骂我喵
Java部分
谷歌最近推荐用Compsoe取代传统xml布局,我一看,赶紧写一个试试,AI生成完一看,跟个flutter似的。丢进反编译一看,跟个答辩似的,请看对比图(这两张图大致在同一个地方)(不开混淆的话可能会好很多):
为什么我能认出来这两个地方在一起呢,这就要从我们的解题思路说起了。
根据题目描述(虽然是最后几个小时加的但相信大家自己看也能看出来),这道题考的是JNI,再看最顶上的几个方法,上面都标着native,肯定就是了:
1 | static { |
通过交叉引用能进到这个回调函数(对应的类)
1 | public final class e implements a { |
是不是跟原本代码里的onClick一模一样。为什么回调函数会生成一个类呢?答案是为了捕获外层变量(闭包嘛)(从构造函数传引用进去)。再来看看逻辑部分,要进入VIP Activated分支,必须要使Hello函数的返回值里包含VIP。而114514那个分支则是出题人乱写的,只要我们打开so看一看Greetings
, World
, CheckVip
这几个函数就能马上意识到(除非你认为出题人的代码在程序运行后会patch自己,但稍加验证就知道并不会)。
原生部分
打开so(可以直接用jeb打开并反编译,这样我们搞Android逆向就不用多买一份IDA了喵),查找Greetings
, World
, CheckVip
这3个函数,发现他们都长得一样
1 | jstring Java_fun_1_zhufn_getmyvip_MainActivity_Greetings(JNIEnv* param0, jobject param1, jstring param2) { |
但是Hello
函数却找不到。众所周知JNI函数有两种加载方式,一种是按照格式命名自动加载,另一种是通过api提交映射表。所以我们打开so的JNI入口点:JNI_OnLoad
函数。(对了我前面说不用IDA是开玩笑的,arm的反编译器一般7和9的盗版都有带)
1 | jint JNI_OnLoad(JavaVM *vm, void *reserved) |
首先开局的三个sub_2436C
非常可疑,他们会进行一些神秘的异或,并且每次会对传入的参数(word_5777C)进行神秘的修改
1 | __int64 __fastcall sub_2436C(__int64 result, __int64 a2) |
提取数据,模拟这个过程,能够得到三个字符串,分别是函数名,签名,类名,这是注册一个JNI函数的必要信息。之前在群里发的跟ai聊天的链接完成的就是到这一步。
1 | unk_5777E: Hello |
1 |
|
下面是JNINativeMethod结构体的定义,你会发现里面没有class,这是因为我们在注册JNI函数时,需要拿到class对象,而不是提供一个类名字符串
1 | typedef struct { |
本题中你可以直接在data段里找到这个结构体
1 | .data:00000000000577D0 off_577D0 DCQ unk_5777E ; DATA XREF: sub_24AE0+44↑o |
也可以在这里找到RegisterNatives
调用
1 | bool __fastcall sub_24AE0(_JNIEnv *a1) |
你可能发现了,其实根本不需要解密那几个字符串,但先不管这一点,打开Hello
函数本体,你可能会嫌c++代码反编译出来就是依托,但相信在我进行了变量重命名后你肯定就懂了。
1 | __int64 __fastcall __JNIFun(_JNIEnv *a1, __int64 a2, __int64 a3) |
如何看出一个c++函数的作用
顺便介绍一下如何看出一个c++函数的作用,以vector_operator_equal
为例,我们点开它:
1 | __int64 __fastcall vector_operator_equal(__int64 a1, __int64 a2) |
看似有很多函数,但大多数点进最深处都是这3种形式:
1 | //成员访问 |
最后在return之前的有效操作只有这个memcmp,因此我们就确定了这个c++函数的作用
1 | bool __fastcall sub_26820(const void *a1, const void *a2, size_t a3) |
最后
解密__JNIFun的主要分支里的字符串,能找到返回vip的那个分支(其实可以直接猜正确结果肯定是两个vector相等)
再把xmmword_1672E那里的数据拿出来,放在ai写的那个解密后面(因为这里接着用了解密函数名时用的异或数)异或一遍就好了。
本题源码(校内访问):https://driver.neu-nex.fun/比赛归档/2024/练习赛文件/GetMyVip.zip